文件读写

修改文件指针位置

write系统调用每次打开一个文件都会保存一个指向文件位置的指针, 当读写操作完成时, 指针会移动到下一个记录位置, 这个指针于文件描述符相关联.这种情况下, 我们如何修改文件中的内容. 答案是系统调用lseek

改变文件当前位置

指针是与文件描述符项关联, 而不是与文件关联, 所以如果两个程序同时打开一个文件, 这时会有两个指针, 两个程序对文件的读操作不会互相干扰.

系统调用lseek可以改变已打开文件的当前位置,

  lseek
目标 使指针指向文件中的指定位置
头文件 #include <sys/type.h> 或者 #include <unistd.h>
函数原型 off_t oldpos = lseek(int fd, off_t dist, int base)
参数 fd: 文件描述符, dist: 移动的距离
  base: SEEK_SET 文件开始 SEEK_CUR 当前位置, SEEK_END 文件结尾
返回值 -1 error, oldpos 指针变化前的位置

lseek改变文件描述符所关联的指针的位置, 新的位置友 dist 和 base 来指定, base 是基准位置, dist 是从基准位置开始的偏移量, 基准位置是从文件的开始(0)、当前位置(1)或文件的结尾(2)

偏移量可以是负的

一些例子

把指针往前偏移一个 utmp 结构

lseek(fd, -(sizeof(struct utmp)), SEEK_CUR);

把指针指到第11个记录的开始位置

lseek(fd, 10 * sizeof(struct utmp), SEEK_SET);

把指针只到文件末尾

lseek(fd, 0, SEEK_END);

返回指针所指向的当前位置

lseek(fd, 0, SEEK_CUR);

终端注销代码

根据上一小节的知识, 可以编写一个函数对注销的用户修改 utmp 中相应的记录

logout_tty(char *line)
{
    int fd;
    struct utmp rec;
    int len = sizeof(struct utmp);
    int reval = -1;

    if (( fd = open(UTMP_FILE, O_RDWR)) == -1)
        return -1;

    while (read(fd, &rec, len) == len)
        if (strncmp(rec.ut_line, line, sizeof(rec.ut_line)) == 0)
        {
            rec.ut_type = DEAD_PROCESS;
            if (time(&rec.ut_time != -1))
                if (lseek(fd, -len, SEEK_CUR) != -1)
                    if (write(fd, &rec, len) == len)
                        retval = 0;
            break;
        }
    if (close(fd) == -1)
        retval = -1;
    return retval;
}
上面函数接受一个line参数, 用于对比 struct utmp 中的 ut_line 成员, 来确定当前记录, 读到当前记录后, 更改属性, 并使用 lseek 将文件指针回退一个 utmp 长度, 并将新的 utmp 写入到文件